﻿#include "ssWsppClientNetwork.h"
#include "../ssServerErrorDefine.h"
#include "message/ssMsgIdDef.h"
#include "message/ssNetMsgHead.h"
#include "log/ssLogger.h"

namespace StarSeeker
{

ssWsppClientNetwork::ssWsppClientNetwork()
{
}

ssWsppClientNetwork::~ssWsppClientNetwork()
{
}

bool ssWsppClientNetwork::StartNetWork(const char* uri)
{
	try {
		// Set logging settings
		m_echoServer.clear_access_channels(websocketpp::log::alevel::all);
		m_echoServer.clear_error_channels(websocketpp::log::alevel::all);

		// Initialize Asio
		m_echoServer.init_asio();

		m_ioService = &m_echoServer.get_io_service();

		// Register our message handler
		m_echoServer.set_message_handler(bind(&ssWsppClientNetwork::OnMessage, this, &m_echoServer, ::_1, ::_2));
		m_echoServer.set_socket_init_handler(bind(&ssWsppClientNetwork::OnSocketInit, this, ::_1, ::_2));
		m_echoServer.set_fail_handler(bind(&ssWsppClientNetwork::OnFail, this, ::_1));
		m_echoServer.set_close_handler(bind(&ssWsppClientNetwork::OnClose, this, ::_1));
		m_echoServer.set_open_handler(bind(&ssWsppClientNetwork::OnOpen, this, ::_1));
		//m_echoServer.set_http_handler(bind(&ssWsppClientNetwork::OnHttp, this, &m_echoServer, ::_1));

		m_uri = uri;
		websocketpp::lib::error_code ec;
		client::connection_ptr con = m_echoServer.get_connection(m_uri, ec);
		if (ec)
		{
			SS_LOG->ErrorEx("create connection error: %s", ec.message().c_str());
			return false;
		}
		m_echoServer.connect(con);

		for (u16 i = 0; i < m_threadCount; i++)
		{
			m_threads.push_back(websocketpp::lib::make_shared<websocketpp::lib::thread>(&client::run, &m_echoServer));
		}

		return true;
	}
	catch (websocketpp::exception const & e) {
		//std::cout << e.what() << std::endl;
		SS_LOG->Error(e.what());
		return false;
	}
	catch (...) {
		return false;
	}
}

void ssWsppClientNetwork::StopNetWork()
{
	try{
		m_echoServer.stop();
		for (u32 i = 0; i < m_threads.size(); ++i)
		{
			m_threads[i]->join();
		}
	}
	catch (websocketpp::exception const & e) {
		//std::cout << "exception: " << e.what() << std::endl;
		SS_LOG->Error(e.what());
	}
}

void ssWsppClientNetwork::DoCloseSocket(u32 sessionId)
{
	m_ioService->post(bind(&ssWsppClientNetwork::HandleClose, this, sessionId));
}

void ssWsppClientNetwork::DoSendData(u32 sessionId, const char* buf, u32 len)
{
	m_ioService->post(bind(&ssWsppClientNetwork::HandleSend, this, sessionId, buf, len));
}

void ssWsppClientNetwork::HandleClose(u32 sessionId)
{
	//找到id
	std::map<u32, ssWsppSession*>::iterator itr = m_sessionId.find(sessionId);
	if (itr != m_sessionId.end())
	{
		try
		{
			m_echoServer.close(itr->second->m_hdl, websocketpp::close::status::normal, "close by server");
		}
		catch (const websocketpp::exception& e)
		{
			SS_LOG->Error(e.what());
		}
		catch (const websocketpp::lib::error_code& e)
		{
			SS_LOG->Error(e.message().c_str());
		}
	}
}

void ssWsppClientNetwork::HandleSend(u32 sessionId, const char* buf, u32 len)
{
	if (buf && len)
	{
		//找到id
		std::map<u32, ssWsppSession*>::iterator itr = m_sessionId.find(sessionId);
		if (itr != m_sessionId.end())
		{
			try
			{
				m_echoServer.send(itr->second->m_hdl, buf, len, websocketpp::frame::opcode::binary);
			}
			catch (const websocketpp::exception& e)
			{
				SS_LOG->Error(e.what());
			}
			catch (const websocketpp::lib::error_code& e)
			{
				SS_LOG->Error(e.message().c_str());
			}
		}
		delete[] buf;
	}
}

void ssWsppClientNetwork::HandleCreate()
{
	websocketpp::lib::error_code ec;
	client::connection_ptr con = m_echoServer.get_connection(m_uri, ec);
	if (ec)
	{
		SS_LOG->ErrorEx("create connection error: %s", ec.message().c_str());
		return;
	}
	m_echoServer.connect(con);
}

void ssWsppClientNetwork::DeleteSession(websocketpp::connection_hdl hdl)
{
	//找到id
	std::map<void*, ssWsppSession*>::iterator itr = m_sessionHdl.find(hdl.lock().get());
	if (itr != m_sessionHdl.end())
	{
		//抛给逻辑
		//m_pNetworkMgr->PostMsg(SS_MSG_ID_DISCONNECT, 0, 0, itr->second);

		//删除连接
		ssWsppSession* session = itr->second;
		OnSessionClose(session->m_sessionID);
		m_sessionId.erase(session->m_sessionID);
		m_sessionHdl.erase(itr);
		//!!需要对象池
		delete session;
	}
}

void ssWsppClientNetwork::OnMessage(client* s, websocketpp::connection_hdl hdl, message_ptr msg)
{
	if (msg->get_opcode() != websocketpp::frame::opcode::binary)
	{
		s->close(hdl, websocketpp::close::status::unsupported_data, "not websocketpp::frame::opcode::binary");
		return;
	}
	
	if (!msg->get_payload().empty())
	{
		u32 len = msg->get_payload().size();
		if (len > 1024*20)
		{
			s->close(hdl, websocketpp::close::status::message_too_big, "data too long");
			return;
		}
		//找到id
		std::map<void*, ssWsppSession*>::iterator itr = m_sessionHdl.find(hdl.lock().get());
		if (itr == m_sessionHdl.end())
		{
			s->close(hdl, websocketpp::close::status::protocol_error, "session id error");
			return;
		}
		//判断包头
		ssNetMsgHead* head = (ssNetMsgHead*)msg->get_payload().data();
		if (head->m_dwLen != len)
		{
			return;
		}
		bool32 ret = itr->second->OnReceive(head);
		if (ret != SS_SUCCESS)
		{
			std::string err = "illegal msg";
			switch (ret)
			{
			case SS_CONNECT_FAST:
				err = "msg too fast";
				break;
			case SS_DISCONNECT:
				err = "socket is disconnect";
				break;
			}
			s->close(hdl, websocketpp::close::status::invalid_payload, err);
			return;
		}
		//!!需要对象池
		char *buf = new char[len];
		memcpy(buf, msg->get_payload().data(), len);
		OnSessionMessage(itr->second->m_sessionID, itr->second->GetIp(), head->m_dwMsgID, buf, (ssNetMsgHead*)buf);
	}
}

void ssWsppClientNetwork::OnSocketInit(websocketpp::connection_hdl hdl, boost::asio::ip::tcp::socket & s)
{
	boost::asio::ip::tcp::no_delay option(true);
	s.set_option(option);
	//分配一个连接对象
	//!!需要对象池
	ssWsppSession* session = new ssWsppSession();
	u32 id = m_idAlloter.GetID();
	session->Init(id, hdl, &s, this);
	m_sessionId.insert(std::pair<u32, ssWsppSession*>(id, session));
	m_sessionHdl.insert(std::pair<void*, ssWsppSession*>(hdl.lock().get(), session));
}

void ssWsppClientNetwork::OnFail(websocketpp::connection_hdl hdl)
{
	DeleteSession(hdl);
}

void ssWsppClientNetwork::OnClose(websocketpp::connection_hdl hdl)
{
	DeleteSession(hdl);
}

void ssWsppClientNetwork::OnOpen(websocketpp::connection_hdl hdl)
{
	//找到id
	std::map<void*, ssWsppSession*>::iterator itr = m_sessionHdl.find(hdl.lock().get());
	if (itr != m_sessionHdl.end())
	{
		if (m_sessionId.size() > m_sessionCount)
		{
			HandleClose(itr->second->m_sessionID);
			return;
		}
		OnNewSession(itr->second->m_sessionID);
	}
}

void ssWsppClientNetwork::CreateConnect()
{
	m_ioService->post(bind(&ssWsppClientNetwork::HandleCreate, this));
}

}
